//server.cc
#include "server.h"
#include "syscall.h"
#include "syscall2.h"
#include <stdio.h>
#include <iostream>
#include <string>
#include "network.h"
#include "post.h"
#include "interrupt.h"
#include "system.h"

ServerLock::ServerLock(char* str)
{
	available = true;
	ownerID = -1;
	ownerBox = -1;
	idQ = new List();
	boxQ = new List();
	name = str;
}

ServerLock::~ServerLock()
{
	delete idQ;
	delete boxQ;
	delete name;
}

void ServerLock::Acquire(int id, int box)
{
	if(available)
	{
		ownerID = id;
		ownerBox = box;
		available = false;
		
		//SEND ACQUIRE MESSAGE
		char* buf = new char[MaxMailSize];
		if (!buf)
		{	
			printf("%s","Acquire response buffer couldn't be created for some reason\n");
			return;
		}
		
		char scName = RPC_LockAcquired;
		memcpy(buf, &scName, 1);
		
		//Create and send mail
		PacketHeader outPktHdr;
		MailHeader outMailHdr;
		
		outPktHdr.to = ownerID;
		outMailHdr.to = ownerBox;
		outMailHdr.from = 1;
		outMailHdr.length = MaxMailSize;
		
		bool success = postOffice->Send(outPktHdr, outMailHdr, buf); 
		if ( !success ) {
		  printf("The postOffice Send for LockAcquired failed. You must not have the other Nachos running.\n");
		}
		
	}else{
		if(id == ownerID && box == ownerBox)
		{
			printf("Owner of lock %s tried to reacquire it!\n", name);
			//SEND ACQUIRE MESSAGE
			char* buf = new char[MaxMailSize];
			if (!buf)
			{	
				printf("%s","Acquire response buffer couldn't be created for some reason\n");
				return;
			}
			
			char scName = RPC_LockAcquired;
			memcpy(buf, &scName, 1);
			
			//Create and send mail
			PacketHeader outPktHdr;
			MailHeader outMailHdr;
			
			outPktHdr.to = ownerID;
			outMailHdr.to = ownerBox;
			outMailHdr.from = 1;
			outMailHdr.length = MaxMailSize;
			
			bool success = postOffice->Send(outPktHdr, outMailHdr, buf); 
			if ( !success ) {
			  printf("The postOffice Send for LockAcquired failed. You must not have the other Nachos running.\n");
			}
		}else{
			int* nextID = new int;
			*nextID = id;
			int* nextBox = new int;
			*nextBox = box;
			idQ->Append(nextID);
			boxQ->Append(nextBox);
			printf("nextID: %d\n", *nextID);
			printf("nextBox: %d\n", *nextBox);
		}
	}
}

void ServerLock::Release(int id, int box)
{
	if(available)
	{
		printf("Attempt to release lock \"%s\", which has not been acquired!\n", name); 
		return;
	}
	
	if(id != ownerID || box != ownerBox)
	{
		printf("Attempt to release lock \"%s\" by a thread that does not hold it!\n", name); 
	}
	
	if(idQ->IsEmpty())
	{
		available = true;
		ownerID = -1;
		ownerBox = -1;
	}else{
		ownerID = *((int*)idQ->Remove());
		ownerBox = *((int*)boxQ->Remove());
		
		printf("relacID: %d\n", ownerID);
		printf("relacBox: %d\n", ownerBox);
		
		//SEND ACQUIRE MESSAGE
		char* buf = new char[MaxMailSize];
		if (!buf)
		{	
			printf("%s","Acquire-from-Release response buffer couldn't be created for some reason\n");
			return;
		}
		
		char scName = RPC_LockAcquired;
		memcpy(buf, &scName, 1);
		
		//Create and send mail
		PacketHeader outPktHdr;
		MailHeader outMailHdr;
		
		outPktHdr.to = ownerID;
		outMailHdr.to = ownerBox;
		outMailHdr.from = 1;
		outMailHdr.length = MaxMailSize;
		
		bool success = postOffice->Send(outPktHdr, outMailHdr, buf); 
		if ( !success ) {
		  printf("The postOffice Send for LockAcquired failed. You must not have the other Nachos running.\n");
		}
		
	}
}

ServerCondition::ServerCondition(char* str)
{
	inUse = false;
	idQ = new std::list<int>();
	boxQ = new std::list<int>();
	name = str;
	lockUsed = -1;
}

ServerCondition::~ServerCondition()
{
	delete idQ;
	delete boxQ;
	delete name;
}

void ServerCondition::Wait(int id, int box, int lockNum)
{
	int hostServer = lockNum / MAX_SERVER_LOCKS;
	int lockID = lockNum % MAX_SERVER_LOCKS;
	if(!inUse)
	{		
		/**//**//**//**//**//**//**//**//**//**//**/
		//check that lock exists somewhere
		
		if(hostServer != machineID)
		{
			//off server
			char* buf = new char[MaxMailSize];
			if (!buf)
			{	
				printf("%s","LockExists buffer couldn't be created for some reason\n");
				return;
			}
			
			char scName = IST_LockExists;
			memcpy(buf, &scName, 1);
			memcpy(buf+1, &lockID,8);
			
			//Create and send mail
			PacketHeader outPktHdr;
			MailHeader outMailHdr;
			
			outPktHdr.to = hostServer;
			outMailHdr.to = 1;
			outMailHdr.from = 1;
			outMailHdr.length = MaxMailSize;
			
			bool success = postOffice->Send(outPktHdr, outMailHdr, buf); 
			if ( !success ) {
			  printf("The postOffice Send for LockExists failed. You must not have the other Nachos running.\n");
			}
			
			//wait for the reply
			replyCond->Wait(replyLock);
			//got the reply
			
			if(!goodLock)
			{
				printf("Cannot Wait using a lock that doesn't exist!\n");
				return;
			}
		
		}else{
			//on server
			if(!createdSL[lockID])
			{
				printf("Cannot Wait using a lock that doesn't exist!\n");
				return;
			}
		}
		
		/**//**//**//**//**//**//**//**//**//**//**/
		
		lockUsed = lockNum;
		printf("Wait ID = %d\n",id);
		idQ->push_back(id);
		boxQ->push_back(box);
		//printf("waitID: %d\n", id);
		//printf("waitox: %d\n", box);
		inUse = true;
		if(hostServer == machineID) serverLockTable[lockID]->Release(id, box);
		else{
			//send a message...
			char* buf = new char[MaxMailSize];
			if (!buf)
			{	
				printf("%s","ReleaseLock buffer couldn't be created for some reason\n");
				return;
			}
			
			char scName = SC_ReleaseLock;
			memcpy(buf, &scName, 1);
			memcpy(buf+1, &lockNum,8);
			
			//Create and send mail
			PacketHeader outPktHdr;
			MailHeader outMailHdr;
			
			outPktHdr.to = hostServer;
			outMailHdr.to = 0;
			outPktHdr.from = id;
			outMailHdr.from = box;
			outMailHdr.length = MaxMailSize;
			
			bool success = postOffice->SendAsOther(outPktHdr, outMailHdr, buf); 
			if ( !success ) {
			  printf("The postOffice Send for ReleaseLock failed. You must not have the other Nachos running.\n");
			}
		}
	}else{
		if(lockNum != lockUsed)
		{
			printf("Tried to Wait on condition \"%s\" using wrong lock!\n", name);
		}else{
			idQ->push_back(id);
			boxQ->push_back(box);
			if(hostServer == machineID) serverLockTable[lockID]->Release(id, box);
			else{
				//send a message...
				char* buf = new char[MaxMailSize];
				if (!buf)
				{	
					printf("%s","ReleaseLock buffer couldn't be created for some reason\n");
					return;
				}
				
				char scName = SC_ReleaseLock;
				memcpy(buf, &scName, 1);
				memcpy(buf+1, &lockNum,8);
				
				//Create and send mail
				PacketHeader outPktHdr;
				MailHeader outMailHdr;
				
				outPktHdr.to = hostServer;
				outMailHdr.to = 0;
				outPktHdr.from = id;
				outMailHdr.from = box;
				outMailHdr.length = MaxMailSize;
				
				bool success = postOffice->SendAsOther(outPktHdr, outMailHdr, buf); 
				if ( !success ) {
				  printf("The postOffice Send for ReleaseLock failed. You must not have the other Nachos running.\n");
				}
			}
			//printf("waitID: %d\n", id);
			//printf("waitox: %d\n", box);
		}
	}
	
}

void ServerCondition::Signal(int lockNum)
{
	/**//**//**//**//**//**//**//**//**//**//**/
	//check that lock exists somewhere
	
	int hostServer = lockNum / MAX_SERVER_LOCKS;
	int lockID = lockNum % MAX_SERVER_LOCKS;
	
	if(hostServer != machineID)
	{
		//off server
		char* buf = new char[MaxMailSize];
		if (!buf)
		{	
			printf("%s","LockExists buffer couldn't be created for some reason\n");
			return;
		}
		
		char scName = IST_LockExists;
		memcpy(buf, &scName, 1);
		memcpy(buf+1, &lockID,8);
		
		//Create and send mail
		PacketHeader outPktHdr;
		MailHeader outMailHdr;
		
		outPktHdr.to = hostServer;
		outMailHdr.to = 1;
		outMailHdr.from = 1;
		outMailHdr.length = MaxMailSize;
		
		bool success = postOffice->Send(outPktHdr, outMailHdr, buf); 
		if ( !success ) {
		  printf("The postOffice Send for LockExists failed. You must not have the other Nachos running.\n");
		}
		
		//wait for the reply
		replyCond->Wait(replyLock);
		//got the reply
		
		if(!goodLock)
		{
			printf("Cannot Wait using a lock that doesn't exist!\n");
			return;
		}
	
	}else{
		//on server
		if(!createdSL[lockID])
		{
			printf("Cannot Wait using a lock that doesn't exist!\n");
			return;
		}
	}
	
	/**//**//**//**//**//**//**//**//**//**//**/
	if(idQ->empty())
	{
		printf("Tried to Signal condition \"%s\", which is empty!\n", name);
		return;
	}
	if(!inUse)
	{
		printf("Tried to Signal condition \"%s\", which is not in use!\n", name);
		return;
	}
	if(lockNum != lockUsed)
	{
		printf("Tried to Signal condition \"%s\" using wrong lock!\n", name);
		return;
	}
	//if args check out, thread now needs to acquire lockNum
	int sigID = idQ->front(); idQ->pop_front();
	int sigBox = boxQ->front(); boxQ->pop_front();
	
	//printf("SigID: %d\n", sigID);
	//printf("SigBox: %d\n", sigBox);
	
	if(idQ->empty())
	{
		inUse = false;
	}
	
	/**/printf("SigID/SigBox = %d / %d\n",sigID,sigBox);
	if(hostServer == machineID) serverLockTable[lockID]->Acquire(sigID, sigBox);
	else{
		//send a message...
		char* buf = new char[MaxMailSize];
		if (!buf)
		{	
			printf("%s","AcquireLock buffer couldn't be created for some reason\n");
			return;
		}
		
		char scName = SC_AcquireLock;
		memcpy(buf, &scName, 1);
		memcpy(buf+1, &lockNum,8);
		
		//Create and send mail
		PacketHeader outPktHdr;
		MailHeader outMailHdr;
		
		outPktHdr.to = hostServer;
		outMailHdr.to = 0;
		outPktHdr.from = sigID;
		outMailHdr.from = sigBox;
		outMailHdr.length = MaxMailSize;
		
		bool success = postOffice->SendAsOther(outPktHdr, outMailHdr, buf); 
		if ( !success ) {
		  printf("The postOffice Send for AcquireLock failed. You must not have the other Nachos running.\n");
		}
	}
}

void ServerCondition::Broadcast(int lockNum)
{
	/**//**//**//**//**//**//**//**//**//**//**/
	//check that lock exists somewhere
	
	int hostServer = lockNum / MAX_SERVER_LOCKS;
	int lockID = lockNum % MAX_SERVER_LOCKS;
	
	if(hostServer != machineID)
	{
		//off server
		char* buf = new char[MaxMailSize];
		if (!buf)
		{	
			printf("%s","LockExists buffer couldn't be created for some reason\n");
			return;
		}
		
		char scName = IST_LockExists;
		memcpy(buf, &scName, 1);
		memcpy(buf+1, &lockID,8);
		
		//Create and send mail
		PacketHeader outPktHdr;
		MailHeader outMailHdr;
		
		outPktHdr.to = hostServer;
		outMailHdr.to = 1;
		outMailHdr.from = 1;
		outMailHdr.length = MaxMailSize;
		
		bool success = postOffice->Send(outPktHdr, outMailHdr, buf); 
		if ( !success ) {
		  printf("The postOffice Send for LockExists failed. You must not have the other Nachos running.\n");
		}
		
		//wait for the reply
		replyCond->Wait(replyLock);
		//got the reply
		
		if(!goodLock)
		{
			printf("Cannot Wait using a lock that doesn't exist!\n");
			return;
		}
	
	}else{
		//on server
		if(!createdSL[lockID])
		{
			printf("Cannot Wait using a lock that doesn't exist!\n");
			return;
		}
	}
	
	/**//**//**//**//**//**//**//**//**//**//**/

	if(idQ->empty())
	{
		printf("Tried to Broadcast condition \"%s\", which is empty!\n", name);
		return;
	}
	if(!inUse)
	{
		printf("Tried to Broadcast condition \"%s\", which is not in use!\n", name);
		return;
	}
	if(lockNum != lockUsed)
	{
		printf("Tried to Broadcast condition \"%s\" using wrong lock!\n", name);
		return;
	}
	
	while(!idQ->empty())
	{
		//calling signal each time means repeating the checks each time
		int sigID = idQ->front(); idQ->pop_front();
		int sigBox = boxQ->front(); boxQ->pop_front();
		if(hostServer == machineID) serverLockTable[lockID]->Acquire(sigID, sigBox);
		else{
			//send a message...
			char* buf = new char[MaxMailSize];
			if (!buf)
			{	
				printf("%s","AcquireLock buffer couldn't be created for some reason\n");
				return;
			}
			
			char scName = SC_AcquireLock;
			memcpy(buf, &scName, 1);
			memcpy(buf+1, &lockNum,8);
			
			//Create and send mail
			PacketHeader outPktHdr;
			MailHeader outMailHdr;
			
			outPktHdr.to = hostServer;
			outMailHdr.to = 0;
			outPktHdr.from = sigID;
			outMailHdr.from = sigBox;
			outMailHdr.length = MaxMailSize;
			
			bool success = postOffice->SendAsOther(outPktHdr, outMailHdr, buf); 
			if ( !success ) {
			  printf("The postOffice Send for AcquireLock failed. You must not have the other Nachos running.\n");
			}
		}
	}
	
	inUse = false;
}

ServerMV::ServerMV(int rows, int cols, char* str)
{
	numRows = rows;
	numCols = cols;
	name = str;
	data = (int*)malloc(sizeof(int) * MAX_MV_LENGTH);
}

ServerMV::~ServerMV()
{
	delete data;
}

void ServerMV::getValue(int r, int c, int id, int box)
{
	if(r < numRows && c < numCols)
	{
		int value = data[(r*numCols) + c];
		
		//send value
		char* buf = new char[MaxMailSize];
		char scName = RPC_MVValue;
		memcpy(buf, &scName, 1);
		memcpy(buf+1, &value, 8);
		
		//Create and send mail
		PacketHeader outPktHdr;
		MailHeader outMailHdr;
		
		outPktHdr.to = id;
		outMailHdr.to = box;
		outMailHdr.from = 1;
		outMailHdr.length = MaxMailSize;
		
		bool success = postOffice->Send(outPktHdr, outMailHdr, buf); 
		if ( !success ) {
		  printf("The postOffice Send for MVValue failed. You must not have the other Nachos running.\n");
		}
		
	}else{
		//send invalid parameter response
		printf("GetValue received invalid parameters\n");
		char* buf = new char[MaxMailSize];
		char scName = RPC_MVInvalid;
		memcpy(buf, &scName, 1);
		
		//Create and send mail
		PacketHeader outPktHdr;
		MailHeader outMailHdr;
		
		outPktHdr.to = id;
		outMailHdr.to = box;
		outMailHdr.from = 1;
		outMailHdr.length = MaxMailSize;
		
		bool success = postOffice->Send(outPktHdr, outMailHdr, buf); 
		if ( !success ) {
		  printf("The postOffice Send for MVInvalid failed. You must not have the other Nachos running.\n");
		}
	}
}

void ServerMV::setValue(int r, int c, int val)
{
	if(r < numRows && c < numCols)
	{
		data[(r*numCols) + c] = val;
	}else{
		//send invalid parameter response
		printf("SetValue received invalid parameters\n");
	}
}

void updateNSL()
{
	//try the next slot first
	if(++nextAvailableSL < MAX_SERVER_LOCKS)
	{
		if(!createdSL[nextAvailableSL]) return;
	}else{
		//otherwise run through the list
		for(int i = 0; i < MAX_SERVER_LOCKS; i++)
		{
			if(!createdSL[i])
			{
				nextAvailableSL = i;
				return;
			}
		}
		//if no slot is found, increment again so syscalls know
		nextAvailableSL++;
	}
}

void updateNSC()
{
	//try the next slot first
	if(++nextAvailableSC < MAX_SERVER_CONDS)
	{
		if(!createdSC[nextAvailableSC]) return;
	}
	//otherwise run through the list
	for(nextAvailableSC = 0; nextAvailableSC < MAX_SERVER_CONDS; nextAvailableSC++)
	{
		if(!createdSC[nextAvailableSC]) return;
	}
	//if no slot is found, increment again so syscalls know
	nextAvailableSC++;
}

void updateNMV()
{
	//try the next slot first
	if(++nextAvailableMV < MAX_SERVER_MV)
	{
		if(!createdMV[nextAvailableMV]) return;
	}
	//otherwise run through the list
	for(nextAvailableMV = 0; nextAvailableMV < MAX_SERVER_MV; nextAvailableMV++)
	{
		if(!createdMV[nextAvailableMV]) return;
	}
	//if no slot is found, increment again so syscalls know
	nextAvailableMV++;
}

void RegisterWithBinder()
{

}

void ServerCreateLock(char* str, int index, int destID, int destBox)
{	
	serverLockTable[index] = new ServerLock(str);
	createdSL[index] = true;
	std::string tmpStr (str);
	lockNameMap[tmpStr] = index;
	
	//send response to client
	char* buf = new char[MaxMailSize];
	if (!buf)
	{	
		printf("%s","Acquire response buffer couldn't be created for some reason\n");
		return;
	}
	
	char scName = RPC_LockCreated;
	memcpy(buf, &scName, 1);
	
	//send client the unique ID of the lock
	int uniqueID = index + (machineID * MAX_SERVER_LOCKS);
	memcpy(buf+1, &uniqueID, 8);
	
	//Create and send mail
	PacketHeader outPktHdr;
	MailHeader outMailHdr;
	
	outPktHdr.to = destID;
	outMailHdr.to = destBox;
	outMailHdr.from = 1;
	outMailHdr.length = MaxMailSize;
	
	bool success = postOffice->Send(outPktHdr, outMailHdr, buf); 
	if ( !success ) {
	  printf("The postOffice Send for LockCreated failed. You must not have the other Nachos running.\n");
	}
	
}

void ServerCreateCondition(char* str, int index, int destID, int destBox)
{
	serverCondTable[index] = new ServerCondition(str);
	createdSC[index] = true;
	std::string tmpStr (str);
	condNameMap[tmpStr] = index;
	
	//send response to client
	char* buf = new char[MaxMailSize];
	if (!buf)
	{	
		printf("%s","Acquire response buffer couldn't be created for some reason\n");
		return;
	}
	
	char scName = RPC_CondCreated;
	memcpy(buf, &scName, 1);
	
	//send client the unique ID of the lock
	int uniqueID = index + (machineID * MAX_SERVER_CONDS);
	memcpy(buf+1, &uniqueID, 8);
	
	//Create and send mail
	PacketHeader outPktHdr;
	MailHeader outMailHdr;
	
	outPktHdr.to = destID;
	outMailHdr.to = destBox;
	outMailHdr.from = 1;
	outMailHdr.length = MaxMailSize;
	
	bool success = postOffice->Send(outPktHdr, outMailHdr, buf); 
	if ( !success ) {
	  printf("The postOffice Send for CondCreated failed. You must not have the other Nachos running.\n");
	}
}

void ServerCreateMV(int rows, int cols, int len, char* str, int index, int destID, int destBox)
{
	ServerMV* newMV = new ServerMV(rows, cols, str); 
	serverMVTable[index] = newMV;
	createdMV[index] = true;
	std::string tmpStr (str);
	MVNameMap[tmpStr] = index;
	
	//send response to client
	char* buf = new char[MaxMailSize];
	if (!buf)
	{	
		printf("%s","Acquire response buffer couldn't be created for some reason\n");
		return;
	}
	
	char scName = RPC_MVCreated;
	memcpy(buf, &scName, 1);
	
	//send client the unique ID of the lock
	int uniqueID = index + (machineID * MAX_SERVER_MV);
	memcpy(buf+1, &uniqueID, 8);
	
	//Create and send mail
	PacketHeader outPktHdr;
	MailHeader outMailHdr;
	
	outPktHdr.to = destID;
	outMailHdr.to = destBox;
	outMailHdr.from = 1;
	outMailHdr.length = MaxMailSize;
	
	bool success = postOffice->Send(outPktHdr, outMailHdr, buf); 
	if ( !success ) {
	  printf("The postOffice Send for MVCreated failed. You must not have the other Nachos running.\n");
	}
}

void PingLockHolders()
{
	std::map<Client,std::list<int>,cmp_client> lockHolders;
	
	for(int i=0; i<MAX_SERVER_LOCKS;i++)
	{
		if(createdSL[i])
		{
			if(!serverLockTable[i]->available)
			{
				Client c =Client(serverLockTable[i]->ownerID,serverLockTable[i]->ownerBox);
				lockHolders[c].push_back(i);
			}
		}
	}
	
	std::map<Client,std::list<int> >::iterator iter;
	
	for(iter=lockHolders.begin();iter!=lockHolders.end();iter++)
	{
		char* buf = new char[MaxMailSize];
		if (!buf)
		{	
			printf("%s","Ping buffer couldn't be created for some reason\n");
			return;
		}
		
		char scName = RPC_PING;
		memcpy(buf, &scName, 1);
		
		//Create and send mail
		PacketHeader outPktHdr;
		MailHeader outMailHdr;
		
		outPktHdr.to = iter->first.machineID;
		outMailHdr.to = iter->first.boxID;
		outMailHdr.from = 1;
		outMailHdr.length = MaxMailSize;
		
		bool success = postOffice->Send(outPktHdr, outMailHdr, buf);
		if(!success)
		{
			printf("Client %i on Machine %i has died",iter->first.boxID,iter->first.machineID);
			while(iter->second.size()>0)
			{
				int lockNum=iter->second.front();
				serverLockTable[lockNum]->Release(iter->first.machineID,iter->first.boxID);
				iter->second.pop_front();
			}
		}
	}
}

void
ServerMain()
{
	printf("INITIALIZING SERVER ID %d...\n", machineID);
	
	for(int i = 0; i < MAX_SERVER_LOCKS; i++)
	{
		createdSL[i] = false;
		destroySL[i] = false;
	}
	
	for(int i = 0; i < MAX_SERVER_CONDS; i++)
	{
		createdSC[i] = false;
		destroySC[i] = false;
	}
	
	for(int i = 0; i < MAX_SERVER_MV; i++)
	{
		createdMV[i] = false;
		destroyMV[i] = false;
	}

	PacketHeader inPktHdr;
	MailHeader inMailHdr;
	char *buf = new char[MaxMailSize];
	
	//REGISTER WITH BINDER
	char* regbuf = new char[MaxMailSize];
	if (!regbuf)
	{	
		printf("%s","Registration buffer couldn't be created for some reason\n");
		return;
	}
	
	char scName = BIND_Add;
	memcpy(regbuf, &scName, 1);
	
	//Create and send mail
	PacketHeader outPktHdr;
	MailHeader outMailHdr;
	
	outPktHdr.to = 0;
	outMailHdr.to = 0;
	outMailHdr.from = 0;
	outMailHdr.length = MaxMailSize;
	
	bool success = postOffice->Send(outPktHdr, outMailHdr, regbuf); 
	if ( !success ) {
	  printf("The postOffice Send for BIND_Add failed. The Binder is not running. Exiting.\n");
	  Exit(-1);
	}
	
	//Create the locks and condition
	lockTableLock = new Lock("lockTableLock");
	condTableLock = new Lock("condTableLock");
	MVTableLock = new Lock("MVTableLock");
	replyLock = new Lock("replyLock");
	replyCond = new Condition("replyCond");
	repliesRemaining = 0;
	queriesToSend = 0;
	serverList[0] = -1;
	serverList[1] = -1;
	serverList[2] = -1;
	serverList[3] = -1;
	serverList[4] = -1;
	offServerID = -1;
	
	replyLock->Acquire();
	
	char* pingbuf = new char[21];
	sprintf(pingbuf,"Server %i Ping\0",machineID);
	Thread *pinger =new Thread(pingbuf);
	pinger->Fork(PingThread,0);
	
	//FORK THE SECOND THREAD
	char* threadbuf = new char[20];
	sprintf(threadbuf,"Server %i IST\0",machineID);
	Thread *t =new Thread(threadbuf);
	t->Fork(InterServerThread,0);
	
	//Fork the thrid thread

	
	
	printf("SERVER RUNNING\n");
	
	while(true)
	{
		postOffice->Receive(0, &inPktHdr, &inMailHdr, buf);
		printf("Server received a message!\n");
		int pktFrom = inPktHdr.from;
		int mailFrom = inMailHdr.from;
		
		printf("PktFrom : MailFrom = %d : %d\n", pktFrom, mailFrom);
		
		char* msgID = new char;
		memcpy(msgID, buf, 1);
		
		switch(*msgID)
		{
			case SC_CreateLock:
			{
				printf("Message type is SC_CreateLock\n");

				lockTableLock->Acquire();
				//extract arguments
				int len = 0;
				memcpy(&len,buf+1,8);
				char* name = new char[len+1];
				
				memmove(name,buf+9,len);
				name[len]='\0';
				printf("~~~lock name: %s  %s\n",name,buf+9);
				/****//****//****//****//****//****//****//****/
				//is the lock already on this server?
				std::map<std::string,int>::iterator it;
				it = lockNameMap.find(name);
				if(it != lockNameMap.end()) //not found
				{
					int lockIndex = it->second;
					//convert to unique ID Number
					lockIndex += machineID * MAX_SERVER_LOCKS;
					
					char* repbuf = new char[MaxMailSize];
					if (!repbuf)
					{	
						printf("%s","Reply buffer couldn't be created for some reason\n");
						lockTableLock->Release();
						break;
					}
					
					char scName = RPC_LockCreated;
					memcpy(repbuf, &scName, 1);
	
					//send client the unique ID of the lock
					memcpy(repbuf+1, &lockIndex, 8);
					
					//Create and send mail
					PacketHeader repPktHdr;
					MailHeader repMailHdr;
					
					repPktHdr.to = pktFrom;
					repMailHdr.to = mailFrom;
					repMailHdr.from = 0;
					repMailHdr.length = MaxMailSize;
					
					printf("Existing lock reply message ID = %d\n",(int)scName);
					
					bool success = postOffice->Send(repPktHdr, repMailHdr, repbuf); 
					if ( !success ) {
					  printf("The postOffice Send for LockCreated failed. You must not have the other Nachos running.\n");
					}
					
 				    lockTableLock->Release();
				    break;
				}
				
				/****//****//****//****//****//****//****//****/
				
				/**//**//**//**//**//**//**//**//**//**//**//**//**//**//**/
				//check if lock exists on other servers
				
				//get server list from Binder
				char* outbuf = new char[MaxMailSize];
				if (!outbuf)
				{	
					printf("%s","Out buffer couldn't be created for some reason\n");
					lockTableLock->Release();
					break;
				}
				
				char scName = BIND_List;
				memcpy(outbuf, &scName, 1);
				
				outPktHdr.to = 0;
				outMailHdr.to = 0;
				outMailHdr.from = 2;
				outMailHdr.length = MaxMailSize;
				
				bool success = postOffice->Send(outPktHdr, outMailHdr, outbuf); 
				if ( !success ) {
				  printf("The postOffice Send for BIND_List failed. The Binder is not running. Exiting.\n");
				  Exit(-1);
				}
				
				postOffice->Receive(2, &inPktHdr, &inMailHdr, buf);
				
				//get num servers
				memcpy(&queriesToSend, buf+1, 8);
				repliesRemaining = queriesToSend-1; //don't wait for self!
				offServerID = -1;
				
				
				//copy the server list
				for(int i = 0; i < queriesToSend; i++)
				{
					char idChar = 0;
					memcpy(&idChar, buf+9+i,1);
					printf("Char %i in list is %d\n",9+i,(int)idChar);
					int serverID = idChar;
					serverList[i] = serverID;
				}
				
				//send the DYH requests
				while(queriesToSend > 0)
				{
					int target = serverList[queriesToSend - 1];
					if(target == machineID)
					{
						queriesToSend--;
						continue;
					}
					
					scName = DYH_Lock;
					memcpy(outbuf, &scName, 1);
					char lenChar = len;
					memcpy(outbuf+1,&lenChar,1);
					memcpy(outbuf+2,name,len);					
					
					outPktHdr.to = target;
					outMailHdr.to = 1;
					outMailHdr.from = 1;
					outMailHdr.length = MaxMailSize;
					
					bool success = postOffice->Send(outPktHdr, outMailHdr, outbuf); 
					if ( !success ) {
					  printf("The postOffice Send for DYH_Lock failed. The other server is not running.\n");
					  repliesRemaining--; //don't wait for a response from a dead server!
					}
					queriesToSend--;
				}
				
				/**/printf("replies to wait for: %d\n", repliesRemaining);
				
				if(repliesRemaining > 0) replyCond->Wait(replyLock); //wait for the IST to process all the replies
				//And when all replies are processed...
				
				if(offServerID != -1) //another server has this lock
				{
					//so send the existing ID to the client
					scName = RPC_LockCreated;
					memcpy(outbuf, &scName, 1);
					
					//send client the index of the lock
					memcpy(outbuf+1, &offServerID, 8);
					
					outPktHdr.to = pktFrom;
					outMailHdr.to = mailFrom;
					outMailHdr.from = 0;
					outMailHdr.length = MaxMailSize;
					
					bool success = postOffice->Send(outPktHdr, outMailHdr, outbuf); 
					if ( !success ) {
					  printf("The postOffice Send for Acquire Lock failed. You must not have the other Nachos running.\n");
					}
					lockTableLock->Release();
					break;
				}
				/**/printf("Lock is not on other server\n");
				//if no other server claimed it, continue as normal
				
				/**//**//**//**//**//**//**//**//**//**//**//**//**//**//**/
				
				//create the lock
				//check there is a free spot
				if(nextAvailableSL >= MAX_SERVER_LOCKS)
				{
					printf("Can't create any more locks!\n");
					lockTableLock->Release();
					break;
				}
				ServerCreateLock(name, nextAvailableSL, pktFrom, mailFrom);
				//update next index
				updateNSL();//nextAvailableSL++;
				
				lockTableLock->Release();
				break;
			}
			case SC_AcquireLock:
			{	
				printf("Message type is SC_AcquireLock\n");
				//extract arguments
				int hostServer = -1;
				int index = 0;
				int uniqueID = 0;
				memcpy(&uniqueID,buf+1,8);
				
				hostServer = uniqueID / MAX_SERVER_LOCKS;
				if(hostServer != machineID) //not on this server
				{
					//forward the message
					printf("Requested lock is on server %d! Forwarding message \n",hostServer);
					
					outPktHdr.to = hostServer;
					outMailHdr.to = 0;
					outPktHdr.from = pktFrom;
					outMailHdr.from = mailFrom;
					outMailHdr.length = MaxMailSize;
					
					bool success = postOffice->SendAsOther(outPktHdr, outMailHdr, buf); 
					if ( !success ) {
					  printf("The postOffice Send for LockCreated failed. You must not have the other Nachos running.\n");
					}
					
					break;
				}
				
				//if lock is on this server
				index = uniqueID % MAX_SERVER_LOCKS;
				
				//validate the index
				if(index < 0 || index >= MAX_SERVER_LOCKS)
				{
					printf("Acquire received invalid index!\n");
					break;
				}
				
				if(!createdSL[index])
				{
					printf("Cannot acquire a lock that doesn't exist!\n");
					break;
				}
				
				//acquire the lock
				serverLockTable[index]->Acquire((int)inPktHdr.from, (int)inMailHdr.from);
				break;
			}
			case SC_ReleaseLock:
			{	
				printf("Message type is SC_ReleaseLock\n");
				//extract arguments
				int hostServer = -1;
				int index = 0;
				int uniqueID = 0;
				memcpy(&uniqueID,buf+1,8);
				
				hostServer = uniqueID / MAX_SERVER_LOCKS;
				if(hostServer != machineID) //not on this server
				{
					//forward the message
					printf("Requested lock is on server %d! Forwarding message \n",hostServer);
					
					outPktHdr.to = hostServer;
					outMailHdr.to = 0;
					outPktHdr.from = pktFrom;
					outMailHdr.from = mailFrom;
					outMailHdr.length = MaxMailSize;
					
					bool success = postOffice->SendAsOther(outPktHdr, outMailHdr, buf); 
					if ( !success ) {
					  printf("The postOffice Send for Release Lock failed. You must not have the other Nachos running.\n");
					}
					
					break;
				}
				
				//if lock is on this server
				index = uniqueID % MAX_SERVER_LOCKS;
				
				//validate the index
				if(index < 0 || index >= MAX_SERVER_LOCKS)
				{
					printf("Release received invalid index!\n");
					break;
				}
				
				if(!createdSL[index])
				{
					printf("Cannot release a lock that doesn't exist!\n");
					break;
				}
				
				//release the lock
				serverLockTable[index]->Release((int)inPktHdr.from, (int)inMailHdr.from);
				
				//check if lock scheduled/ready to die
				if(destroySL[index])
				{
					if(serverLockTable[index]->available)
					{
						lockNameMap.erase(serverLockTable[index]->name);
						delete serverLockTable[index];
						createdSL[index] = false;
						destroySL[index] = false;
						
						//set next SL to index if necessary
						if(nextAvailableSL >= MAX_SERVER_LOCKS)
						{
							nextAvailableSL = index;
						}
						printf("Destroyed lock %d!\n", index);
					}
				}
				
				break;
			}
			case SC_DestroyLock:
			{	
				printf("Message type is SC_DestroyLock\n");
				//extract arguments
				int hostServer = -1;
				int index = 0;
				int uniqueID = 0;
				memcpy(&uniqueID,buf+1,8);
				
				hostServer = uniqueID / MAX_SERVER_LOCKS;
				if(hostServer != machineID) //not on this server
				{
					//forward the message
					printf("Requested lock is on server %d! Forwarding message \n",hostServer);
					
					outPktHdr.to = hostServer;
					outMailHdr.to = 0;
					outPktHdr.from = pktFrom;
					outMailHdr.from = mailFrom;
					outMailHdr.length = MaxMailSize;
					
					bool success = postOffice->SendAsOther(outPktHdr, outMailHdr, buf); 
					if ( !success ) {
					  printf("The postOffice Send for Destroy Lock failed. You must not have the other Nachos running.\n");
					}
					
					break;
				}
				
				//if lock is on this server
				index = uniqueID % MAX_SERVER_LOCKS;
				
				//validate the index
				if(index < 0 || index >= MAX_SERVER_LOCKS)
				{
					printf("Destroy lock received invalid index!\n");
					break;
				}
				
				if(!createdSL[index])
				{
					printf("Cannot destroy a lock that doesn't exist!\n");
					break;
				}
				
				//check if lock can die
				
				if(serverLockTable[index]->available)
				{
					lockNameMap.erase(serverLockTable[index]->name);
					delete serverLockTable[index];
					createdSL[index] = false;
					destroySL[index] = false;
					
					//set next SL to index if necessary
					if(nextAvailableSL >= MAX_SERVER_LOCKS)
					{
						nextAvailableSL = index;
					}
					printf("Destroyed lock %d!\n", index);
				}else{
					//schedule for destruction
					destroySL[index] = true;
				}
							
				break;
			}
			case SC_CreateCondition:
			{
				printf("Message type is SC_CreateCondition\n");
				
				condTableLock->Acquire();
				//extract arguments
				int len = 0;
				memcpy(&len,buf+1,8);
				char* name = new char[len+1];
				memcpy(name,buf+9,len);
				
				/****//****//****//****//****//****//****//****/
				//is the lock already on this server?
				std::map<std::string,int>::iterator it;
				it = condNameMap.find(name);
				if(it != condNameMap.end()) //found
				{
					int condIndex = it->second;
					//convert to unique ID Number
					condIndex += machineID * MAX_SERVER_CONDS;
					
					char* repbuf = new char[MaxMailSize];
					if (!repbuf)
					{	
						printf("%s","Reply buffer couldn't be created for some reason\n");
						condTableLock->Release();
						break;
					}
					
					char scName = RPC_CondCreated;
					memcpy(repbuf, &scName, 1);
	
					//send client the unique ID of the lock
					memcpy(repbuf+1, &condIndex, 8);
					
					//Create and send mail
					PacketHeader repPktHdr;
					MailHeader repMailHdr;
					
					repPktHdr.to = pktFrom;
					repMailHdr.to = mailFrom;
					repMailHdr.from = 0;
					repMailHdr.length = MaxMailSize;
					
					bool success = postOffice->Send(repPktHdr, repMailHdr, repbuf); 
					if ( !success ) {
					  printf("The postOffice Send for CondCreated failed. You must not have the other Nachos running.\n");
					}
					
 				    condTableLock->Release();
				    break;
				}
				
				/****//****//****//****//****//****//****//****/
				
				/**//**//**//**//**//**//**//**//**//**//**//**//**//**//**/
				//check if lock exists on other servers
				
				//get server list from Binder
				char* outbuf = new char[MaxMailSize];
				if (!outbuf)
				{	
					printf("%s","Out buffer couldn't be created for some reason\n");
					condTableLock->Release();
					break;
				}
				
				char scName = BIND_List;
				memcpy(outbuf, &scName, 1);
				
				outPktHdr.to = 0;
				outMailHdr.to = 0;
				outMailHdr.from = 2;
				outMailHdr.length = MaxMailSize;
				
				bool success = postOffice->Send(outPktHdr, outMailHdr, outbuf); 
				if ( !success ) {
				  printf("The postOffice Send for BIND_List failed. The Binder is not running. Exiting.\n");
				  Exit(-1);
				}
				
				postOffice->Receive(2, &inPktHdr, &inMailHdr, buf);
				
				//get num servers
				memcpy(&queriesToSend, buf+1, 8);
				repliesRemaining = queriesToSend-1; //don't wait for self!
				offServerID = -1;
				
				
				//copy the server list
				for(int i = 0; i < queriesToSend; i++)
				{
					char idChar = 0;
					memcpy(&idChar, buf+9+i,1);
					int serverID = idChar;
					serverList[i] = serverID;
				}
				
				//send the DYH requests
				while(queriesToSend > 0)
				{
					int target = serverList[queriesToSend - 1];
					if(target == machineID)
					{
						queriesToSend--;
						continue;
					}
					
					scName = DYH_Cond;
					memcpy(outbuf, &scName, 1);
					char lenChar = len;
					memcpy(outbuf+1,&lenChar,1);
					memcpy(outbuf+2,name,len);					
					
					outPktHdr.to = target;
					outMailHdr.to = 1;
					outMailHdr.from = 1;
					outMailHdr.length = MaxMailSize;
					
					bool success = postOffice->Send(outPktHdr, outMailHdr, outbuf); 
					if ( !success ) {
					  printf("The postOffice Send for DYH_Cond failed. The other server is not running.\n");
					  repliesRemaining--; //don't wait for a response from a dead server!
					}
					queriesToSend--;
				}
				
				/**/printf("replies to wait for: %d\n", repliesRemaining);
				
				if(repliesRemaining > 0) replyCond->Wait(replyLock); //wait for the IST to process all the replies
				//And when all replies are processed...
				
				if(offServerID != -1) //another server has this lock
				{
					//so send the existing ID to the client
					scName = RPC_CondCreated;
					memcpy(outbuf, &scName, 1);
					
					//send client the index of the lock
					memcpy(outbuf+1, &offServerID, 8);
					
					outPktHdr.to = pktFrom;
					outMailHdr.to = mailFrom;
					outMailHdr.from = 0;
					outMailHdr.length = MaxMailSize;
					
					bool success = postOffice->Send(outPktHdr, outMailHdr, outbuf); 
					if ( !success ) {
					  printf("The postOffice Send for Create Cond failed. You must not have the other Nachos running.\n");
					}
					condTableLock->Release();
					break;
				}
				/**/printf("Cond is not on other server\n");
				//if no other server claimed it, continue as normal
				
				/**//**//**//**//**//**//**//**//**//**//**//**//**//**//**/
				
				//check there is a free spot
				if(nextAvailableSC >= MAX_SERVER_CONDS)
				{
					printf("Can't create any more conditions!\n");
					condTableLock->Release();
					break;
				}
				//create the lock
				ServerCreateCondition(name, nextAvailableSC, pktFrom, mailFrom);
				//update next index
				updateNSC(); //nextAvailableSC++;
				condTableLock->Release();
				break;
			}
			case SC_Wait:
			{
				printf("Message type is SC_Wait\n");
				//extract arguments
				int hostServer = -1;
				int index = 0;
				int uniqueID = 0;
				memcpy(&uniqueID,buf+1,8);
				
				hostServer = uniqueID / MAX_SERVER_CONDS;
				if(hostServer != machineID) //not on this server
				{
					//forward the message
					printf("Requested cond is on server %d! Forwarding message \n",hostServer);
					
					outPktHdr.to = hostServer;
					outMailHdr.to = 0;
					outPktHdr.from = pktFrom;
					outMailHdr.from = mailFrom;
					outMailHdr.length = MaxMailSize;
					
					bool success = postOffice->SendAsOther(outPktHdr, outMailHdr, buf); 
					if ( !success ) {
					  printf("The postOffice Send for Wait failed. You must not have the other Nachos running.\n");
					}
					
					break;
				}
				printf("Requested cond is on this server!\n");
				
				//if cond is on this server
				index = uniqueID % MAX_SERVER_CONDS;
				
				//validate the index
				if(index < 0 || index >= MAX_SERVER_CONDS)
				{
					printf("Wait received invalid index '%d'!\n", index);
					break;
				}
				
				if(!createdSC[index])
				{
					printf("Cannot wait on a condition that doesn't exist!\n");
					break;
				}
				
				int lockNum = 0;
				memcpy(&lockNum,buf+9,8);
				if(lockNum < 0 )
				{
					printf("Wait received invalid lock index '%d'!\n",lockNum);
					break;
				}
				
				/*if(!createdSL[lockNum])
				{
					printf("Cannot Wait using a lock that doesn't exist!\n");
					break;
				}*/
				
				//Wait
				serverCondTable[index]->Wait((int)inPktHdr.from, (int)inMailHdr.from, lockNum);
				break;
			}
			case SC_Signal:
			{
				printf("Message type is SC_Signal\n");
				//extract arguments
				int hostServer = -1;
				int index = 0;
				int uniqueID = 0;
				memcpy(&uniqueID,buf+1,8);
				
				hostServer = uniqueID / MAX_SERVER_CONDS;
				if(hostServer != machineID) //not on this server
				{
					//forward the message
					printf("Requested cond is on server %d! Forwarding message \n",hostServer);
					
					outPktHdr.to = hostServer;
					outMailHdr.to = 0;
					outPktHdr.from = pktFrom;
					outMailHdr.from = mailFrom;
					outMailHdr.length = MaxMailSize;
					
					bool success = postOffice->SendAsOther(outPktHdr, outMailHdr, buf); 
					if ( !success ) {
					  printf("The postOffice Send for Signal failed. You must not have the other Nachos running.\n");
					}
					
					break;
				}
				
				//if cond is on this server
				index = uniqueID % MAX_SERVER_CONDS;
				
				//validate the index
				if(index < 0 || index >= MAX_SERVER_CONDS)
				{
					printf("Signal received invalid index!\n");
					break;
				}
				
				if(!createdSC[index])
				{
					printf("Cannot signal a condition that doesn't exist!\n");
					break;
				}
				
				int lockNum = 0;
				memcpy(&lockNum,buf+9,8);
				
				//validate the lock
				if(lockNum < 0)
				{
					printf("Signal received invalid lock index!\n");
					break;
				}
				
				/*if(!createdSL[lockNum])
				{
					printf("Cannot Signal a lock that doesn't exist!\n");
					break;
				}*/
				
				//Signal
				serverCondTable[index]->Signal(lockNum);
				
				//check if lock scheduled/ready to die
				if(destroySC[index])
				{
					if(!serverCondTable[index]->inUse)
					{
						condNameMap.erase(serverCondTable[index]->name);
						delete serverCondTable[index];
						createdSC[index] = false;
						destroySC[index] = false;
						
						//set next SL to index if necessary
						if(nextAvailableSC >= MAX_SERVER_CONDS)
						{
							nextAvailableSC = index;
						}
						printf("Destroyed condition %d!\n", index);
					}
				}
				
				break;
			}
			case SC_Broadcast:
			{
				printf("Message type is SC_Broadcast\n");
				//extract arguments
				int hostServer = -1;
				int index = 0;
				int uniqueID = 0;
				memcpy(&uniqueID,buf+1,8);
				
				hostServer = uniqueID / MAX_SERVER_CONDS;
				if(hostServer != machineID) //not on this server
				{
					//forward the message
					printf("Requested cond is on server %d! Forwarding message \n",hostServer);
					
					outPktHdr.to = hostServer;
					outMailHdr.to = 0;
					outPktHdr.from = pktFrom;
					outMailHdr.from = mailFrom;
					outMailHdr.length = MaxMailSize;
					
					bool success = postOffice->SendAsOther(outPktHdr, outMailHdr, buf); 
					if ( !success ) {
					  printf("The postOffice Send for Broadcast failed. You must not have the other Nachos running.\n");
					}
					
					break;
				}
				
				//if cond is on this server
				index = uniqueID % MAX_SERVER_CONDS;
				
				//validate the index
				if(index < 0 || index >= MAX_SERVER_CONDS)
				{
					printf("Broadcast received invalid index!\n");
					break;
				}
				
				if(!createdSC[index])
				{
					printf("Cannot broadcast a condition that doesn't exist!\n");
					break;
				}
				
				int lockNum = 0;
				memcpy(&lockNum,buf+9,8);
				
				//validate the lock
				if(lockNum < 0)
				{
					printf("Broadcast received invalid lock index!\n");
					break;
				}
				
				/*if(!createdSL[lockNum])
				{
					printf("Cannot Broadcast using a lock that doesn't exist!\n");
					break;
				}*/
				
				
				
				//Broadcast
				serverCondTable[index]->Broadcast(lockNum);
				
				if(destroySC[index])
				{
					if(!serverCondTable[index]->inUse)
					{
						condNameMap.erase(serverCondTable[index]->name);
						delete serverCondTable[index];
						createdSC[index] = false;
						destroySC[index] = false;
						
						//set next SL to index if necessary
						if(nextAvailableSC >= MAX_SERVER_CONDS)
						{
							nextAvailableSC = index;
						}
						printf("Destroyed condition %d!\n", index);
					}
				}
				break;
			}
			case SC_DestroyCondition:
			{	
				printf("Message type is SC_DestroyCondition\n");
				//extract arguments
				int hostServer = -1;
				int index = 0;
				int uniqueID = 0;
				memcpy(&uniqueID,buf+1,8);
				
				hostServer = uniqueID / MAX_SERVER_CONDS;
				if(hostServer != machineID) //not on this server
				{
					//forward the message
					printf("Requested cond is on server %d! Forwarding message \n",hostServer);
					
					outPktHdr.to = hostServer;
					outMailHdr.to = 0;
					outPktHdr.from = pktFrom;
					outMailHdr.from = mailFrom;
					outMailHdr.length = MaxMailSize;
					
					bool success = postOffice->SendAsOther(outPktHdr, outMailHdr, buf); 
					if ( !success ) {
					  printf("The postOffice Send for Destroy Condition failed. You must not have the other Nachos running.\n");
					}
					
					break;
				}
				
				//if cond is on this server
				index = uniqueID % MAX_SERVER_CONDS;
				
				//validate the index
				if(index < 0 || index >= MAX_SERVER_CONDS)
				{
					printf("Destroy condition received invalid index!\n");
					break;
				}
				
				if(!createdSC[index])
				{
					printf("Cannot destroy a condition that doesn't exist!\n");
					break;
				}
				
				//check if cond can die
				
				if(!serverCondTable[index]->inUse)
				{
					condNameMap.erase(serverCondTable[index]->name);
					delete serverCondTable[index];
					createdSC[index] = false;
					destroySC[index] = false;
					
					//set next SC to index if necessary
					if(nextAvailableSC >= MAX_SERVER_CONDS)
					{
						nextAvailableSC = index;
					}
					printf("Destroyed condition %d!\n", index);
				}else{
					//schedule for destruction
					destroySC[index] = true;
				}
							
				break;
			}
			case SC_CreateMV:
			{
				printf("Message type is SC_CreateMV\n");
				MVTableLock->Acquire();
				//check there is a free spot
				//extract arguments
				char rows = 0;
				memcpy(&rows,buf+1,1);
				char cols = 0;
				memcpy(&cols,buf+2,1);
				char len = 0;
				memcpy(&len,buf+3,1);
				char* name = new char[28];
				memcpy(name,buf+4,(int)len);
				
				/****//****//****//****//****//****//****//****/
				//is the MV already on this server?
				std::map<std::string,int>::iterator it;
				it = MVNameMap.find(name);
				if(it != MVNameMap.end()) //found
				{
					int mvIndex = it->second;
					//convert to unique ID Number
					mvIndex += machineID * MAX_SERVER_MV;
					
					char* repbuf = new char[MaxMailSize];
					if (!repbuf)
					{	
						printf("%s","Reply buffer couldn't be created for some reason\n");
						condTableLock->Release();
						break;
					}
					
					char scName = RPC_MVCreated;
					memcpy(repbuf, &scName, 1);
	
					//send client the unique ID of the lock
					memcpy(repbuf+1, &mvIndex, 8);
					
					//Create and send mail
					PacketHeader repPktHdr;
					MailHeader repMailHdr;
					
					repPktHdr.to = pktFrom;
					repMailHdr.to = mailFrom;
					repMailHdr.from = 0;
					repMailHdr.length = MaxMailSize;
					
					bool success = postOffice->Send(repPktHdr, repMailHdr, repbuf); 
					if ( !success ) {
					  printf("The postOffice Send for MVCreated failed. You must not have the other Nachos running.\n");
					}
					
 				    MVTableLock->Release();
				    break;
				}
				
				/****//****//****//****//****//****//****//****/
				
				/**//**//**//**//**//**//**//**//**//**//**//**//**//**//**/
				//check if MV exists on other servers
				
				//get server list from Binder
				char* outbuf = new char[MaxMailSize];
				if (!outbuf)
				{	
					printf("%s","Out buffer couldn't be created for some reason\n");
					MVTableLock->Release();
					break;
				}
				
				char scName = BIND_List;
				memcpy(outbuf, &scName, 1);
				
				outPktHdr.to = 0;
				outMailHdr.to = 0;
				outMailHdr.from = 2;
				outMailHdr.length = MaxMailSize;
				
				bool success = postOffice->Send(outPktHdr, outMailHdr, outbuf); 
				if ( !success ) {
				  printf("The postOffice Send for BIND_List failed. The Binder is not running. Exiting.\n");
				  Exit(-1);
				}
				
				postOffice->Receive(2, &inPktHdr, &inMailHdr, buf);
				
				//get num servers
				memcpy(&queriesToSend, buf+1, 8);
				repliesRemaining = queriesToSend-1; //don't wait for self!
				offServerID = -1;
				
				
				//copy the server list
				for(int i = 0; i < queriesToSend; i++)
				{
					char idChar = 0;
					memcpy(&idChar, buf+9+i,1);
					int serverID = idChar;
					serverList[i] = serverID;
				}
				
				//send the DYH requests
				while(queriesToSend > 0)
				{
					int target = serverList[queriesToSend - 1];
					if(target == machineID)
					{
						queriesToSend--;
						continue;
					}
					
					scName = DYH_MV;
					memcpy(outbuf, &scName, 1);
					memcpy(outbuf+1,&len,1);
					memcpy(outbuf+2,name,(int)len);					
					
					outPktHdr.to = target;
					outMailHdr.to = 1;
					outMailHdr.from = 1;
					outMailHdr.length = MaxMailSize;
					
					bool success = postOffice->Send(outPktHdr, outMailHdr, outbuf); 
					if ( !success ) {
					  printf("The postOffice Send for DYH_MV failed. The other server is not running.\n");
					  repliesRemaining--; //don't wait for a response from a dead server!
					}
					queriesToSend--;
				}
				
				/**/printf("replies to wait for: %d\n", repliesRemaining);
				
				if(repliesRemaining > 0) replyCond->Wait(replyLock); //wait for the IST to process all the replies
				//And when all replies are processed...
				
				if(offServerID != -1) //another server has this lock
				{
					//so send the existing ID to the client
					scName = RPC_MVCreated;
					memcpy(outbuf, &scName, 1);
					
					//send client the index of the lock
					memcpy(outbuf+1, &offServerID, 8);
					
					outPktHdr.to = pktFrom;
					outMailHdr.to = mailFrom;
					outMailHdr.from = 0;
					outMailHdr.length = MaxMailSize;
					
					bool success = postOffice->Send(outPktHdr, outMailHdr, outbuf); 
					if ( !success ) {
					  printf("The postOffice Send for CreatedMV failed. You must not have the other Nachos running.\n");
					}
					MVTableLock->Release();
					break;
				}
				/**/printf("Cond is not on other server\n");
				//if no other server claimed it, continue as normal
				
				/**//**//**//**//**//**//**//**//**//**//**//**//**//**//**/
				
				
				if(nextAvailableMV >= MAX_SERVER_MV)
				{
					printf("Can't create any more MVs!\n");
					MVTableLock->Release();
					break;
				}
				
				//create the MV
				ServerCreateMV((int)rows, (int)cols, (int)len, name, nextAvailableMV, pktFrom, mailFrom);
				//update next index
				updateNMV(); //nextAvailableMV++;
				MVTableLock->Release();
				break;
			}
			case SC_GetMV:
			{
				printf("Message type is SC_GetMV\n");
				//extract arguments
				int hostServer = -1;
				int index = 0;
				int uniqueID = 0;
				memcpy(&uniqueID,buf+1,8);
				
				hostServer = uniqueID / MAX_SERVER_MV;
				if(hostServer != machineID) //not on this server
				{
					//forward the message
					printf("Requested MV is on server %d! Forwarding message \n",hostServer);
					
					outPktHdr.to = hostServer;
					outMailHdr.to = 0;
					outPktHdr.from = pktFrom;
					outMailHdr.from = mailFrom;
					outMailHdr.length = MaxMailSize;
					
					bool success = postOffice->SendAsOther(outPktHdr, outMailHdr, buf); 
					if ( !success ) {
					  printf("The postOffice Send for GetMV failed. You must not have the other Nachos running.\n");
					}
					
					break;
				}
				
				//if lock is on this server
				index = uniqueID % MAX_SERVER_MV;
				
				//validate the index
				if(index < 0 || index >= MAX_SERVER_MV)
				{
					printf("GetMV received invalid index!\n");
					break;
				}
				
				if(!createdMV[index])
				{
					printf("Cannot get value from a MV that doesn't exist!\n");
					break;
				}
				
				//printf("Getting value of MV[%d][?]\n", index);
				
				//get row/col
				int *row = new int;
				int *col = new int;
				memcpy(row,buf+9,8);
				memcpy(col,buf+17,8);
				//get the value
				//if(serverMVTable[index] == NULL) printf("GOD DAMMIT how can that be null?\n");
				printf("Getting value of MV[%d][%d][%d]\n", index,  *row, *col);
				serverMVTable[index]->getValue(*row, *col, (int)inPktHdr.from, (int)inMailHdr.from);
				break;
			}
			case SC_SetMV:
			{
				printf("Message type is SC_SetMV\n");
				//extract arguments
				int hostServer = -1;
				int index = 0;
				int uniqueID = 0;
				memcpy(&uniqueID,buf+1,8);
				
				hostServer = uniqueID / MAX_SERVER_MV;
				if(hostServer != machineID) //not on this server
				{
					//forward the message
					printf("Requested lock is on server %d! Forwarding message \n",hostServer);
					
					outPktHdr.to = hostServer;
					outMailHdr.to = 0;
					outPktHdr.from = pktFrom;
					outMailHdr.from = mailFrom;
					outMailHdr.length = MaxMailSize;
					
					bool success = postOffice->SendAsOther(outPktHdr, outMailHdr, buf); 
					if ( !success ) {
					  printf("The postOffice Send for GetMV failed. You must not have the other Nachos running.\n");
					}
					
					break;
				}
				
				//if lock is on this server
				index = uniqueID % MAX_SERVER_MV;
				
				//validate the index
				if(index < 0 || index >= MAX_SERVER_MV)
				{
					printf("SetMV received invalid index!\n");
					break;
				}
				
				if(!createdMV[index])
				{
					printf("Cannot set value of a MV that doesn't exist!\n");
					break;
				}
				
				//get row/col
				char r_c = 0;
				char c_c = 0;
				memcpy(&r_c,buf+9,1);
				memcpy(&c_c,buf+10,1);
				int row = (int) r_c;
				int col = (int) c_c;
				
				//get value
				int value = 0;
				memcpy(&value,buf+11,8);
				
				printf("Setting value of MV[%d][%d][%d] to %d\n", index,  row, col, value);
				
				//set the value
				serverMVTable[index]->setValue(row, col, value);
				break;
			}
			case SC_DestroyMV:
			{
				printf("Message type is SC_DestroyMV\n");
				//extract arguments
				int hostServer = -1;
				int index = 0;
				int uniqueID = 0;
				memcpy(&uniqueID,buf+1,8);
				
				hostServer = uniqueID / MAX_SERVER_MV;
				if(hostServer != machineID) //not on this server
				{
					//forward the message
					printf("Requested lock is on server %d! Forwarding message \n",hostServer);
					
					outPktHdr.to = hostServer;
					outMailHdr.to = 0;
					outPktHdr.from = pktFrom;
					outMailHdr.from = mailFrom;
					outMailHdr.length = MaxMailSize;
					
					bool success = postOffice->SendAsOther(outPktHdr, outMailHdr, buf); 
					if ( !success ) {
					  printf("The postOffice Send for GetMV failed. You must not have the other Nachos running.\n");
					}
					
					break;
				}
				
				//if lock is on this server
				index = uniqueID % MAX_SERVER_MV;
				
				//validate the index
				if(index < 0 || index >= MAX_SERVER_MV)
				{
					printf("DestroyMV received invalid index!\n");
					break;
				}
				
				if(!createdMV[index])
				{
					printf("Cannot destroy a MV that doesn't exist!\n");
					break;
				}
				
				MVNameMap.erase(serverMVTable[index]->name);
				delete serverMVTable[index];
				createdMV[index] = false;
				break;
			}
			default:
			{
				printf("Server received unknown message type: %c\n", (*msgID));
				break;
			}
		}
		currentThread->Yield();
	}
}

void PingThread(int doesNothing)
{
	currentThread->SetMBID();
	printf("Starting up pinging thread\n");
	lastPingTime=time(NULL);
	
	while(true)
	{
		if(time(NULL)-lastPingTime>10)
		{
			printf("pinging \n");
			PingLockHolders();
			lastPingTime=time(NULL);
		}
		currentThread->Yield();
	}
}

void InterServerThread(int doesNothing)
{
	currentThread->SetMBID();
	printf("INITIALIZING SERVER %d IST...\n", machineID);
	
	PacketHeader inPktHdr;
	MailHeader inMailHdr;
	char *buf = new char[MaxMailSize];
	
	printf("SERVER %d IST RUNNING!\n", machineID);
	
	while(true)
	{
		postOffice->Receive(1, &inPktHdr, &inMailHdr, buf);
		
		char* msgID = new char;
		memcpy(msgID, buf, 1);
		
		switch(*msgID)
		{
			case DYH_Lock:
			{
				printf("Server %d IST received %s message!\n", machineID, "DYH_Lock");
				//extract name and len
				char lenChar = 0;
				memcpy(&lenChar, buf+1, 1);
				int len = lenChar;
				char* name = new char[32];
				memcpy(name, buf+2, len);
				
				/**/printf("DYH_Lock received len/name %d/%s\n",len,name);
				
				lockTableLock->Acquire();
				//check if lock exists on this server
				std::map<std::string,int>::iterator it;
				it = lockNameMap.find(name);
				if(it == lockNameMap.end()) //not found
				{
					char* regbuf = new char[MaxMailSize];
					if (!regbuf)
					{	
						printf("%s","Registration buffer couldn't be created for some reason\n");
						lockTableLock->Release();
						break;
					}
					
					char scName = NO_Lock;
					memcpy(regbuf, &scName, 1);
					
					//Create and send mail
					PacketHeader outPktHdr;
					MailHeader outMailHdr;
					
					outPktHdr.to = inPktHdr.from; 
					outMailHdr.to = 1; //send reply to IST
					outMailHdr.from = 1;
					outMailHdr.length = MaxMailSize;
					
					bool success = postOffice->Send(outPktHdr, outMailHdr, regbuf); 
					if ( !success ) {
					  printf("The postOffice Send for NO_Lock failed. The other server is not running!\n");
					  lockTableLock->Release();
					  break;
					}
				}else{
					int lockIndex = it->second;
					//convert to unique ID Number
					lockIndex += machineID * MAX_SERVER_LOCKS;
					
					char* regbuf = new char[MaxMailSize];
					if (!regbuf)
					{	
						printf("%s","Registration buffer couldn't be created for some reason\n");
						lockTableLock->Release();
						break;
					}
					
					char scName = HAVE_Lock;
					memcpy(regbuf, &scName, 1);
					memcpy(regbuf+1, &lockIndex, 8);
					
					//Create and send mail
					PacketHeader outPktHdr;
					MailHeader outMailHdr;
					
					outPktHdr.to = inPktHdr.from; 
					outMailHdr.to = 1; //send reply to IST
					outMailHdr.from = 1;
					outMailHdr.length = MaxMailSize;
					
					bool success = postOffice->Send(outPktHdr, outMailHdr, regbuf); 
					if ( !success ) {
					  printf("The postOffice Send for HAVE_Lock failed. The other server is not running!\n");
					  lockTableLock->Release();
					  break;
					}
				}
				lockTableLock->Release();
				break;
			}
			
			case DYH_Cond:
			{
				printf("Server %d IST received %s message!\n", machineID, "DYH_Cond");
				//extract name and len
				char lenChar = 0;
				memcpy(&lenChar, buf+1, 1);
				int len = lenChar;
				char* name = new char[32];
				memcpy(name, buf+2, len);
				
				/**/printf("DYH_Cond received len/name %d/%s\n",len,name);
				
				condTableLock->Acquire();
				//check if lock exists on this server
				std::map<std::string,int>::iterator it;
				it = condNameMap.find(name);
				if(it == condNameMap.end()) //not found
				{
					char* regbuf = new char[MaxMailSize];
					if (!regbuf)
					{	
						printf("%s","Registration buffer couldn't be created for some reason\n");
						condTableLock->Release();
						break;
					}
					
					char scName = NO_Cond;
					memcpy(regbuf, &scName, 1);
					
					//Create and send mail
					PacketHeader outPktHdr;
					MailHeader outMailHdr;
					
					outPktHdr.to = inPktHdr.from; 
					outMailHdr.to = 1; //send reply to IST
					outMailHdr.from = 1;
					outMailHdr.length = MaxMailSize;
					
					bool success = postOffice->Send(outPktHdr, outMailHdr, regbuf); 
					if ( !success ) {
					  printf("The postOffice Send for NO_Cond failed. The other server is not running!\n");
					  condTableLock->Release();
					  break;
					}
				}else{
					int condIndex = it->second;
					//convert to unique ID Number
					condIndex += machineID * MAX_SERVER_CONDS;
					
					char* regbuf = new char[MaxMailSize];
					if (!regbuf)
					{	
						printf("%s","Registration buffer couldn't be created for some reason\n");
						condTableLock->Release();
						break;
					}
					
					char scName = HAVE_Cond;
					memcpy(regbuf, &scName, 1);
					memcpy(regbuf+1, &condIndex, 8);
					
					//Create and send mail
					PacketHeader outPktHdr;
					MailHeader outMailHdr;
					
					outPktHdr.to = inPktHdr.from; 
					outMailHdr.to = 1; //send reply to IST
					outMailHdr.from = 1;
					outMailHdr.length = MaxMailSize;
					
					bool success = postOffice->Send(outPktHdr, outMailHdr, regbuf); 
					if ( !success ) {
					  printf("The postOffice Send for HAVE_Cond failed. The other server is not running!\n");
					  condTableLock->Release();
					  break;
					}
				}
				condTableLock->Release();
				break;
			}
			
			case DYH_MV:
			{
				printf("Server %d IST received %s message!\n", machineID, "DYH_MV");
				//extract name and len
				char lenChar = 0;
				memcpy(&lenChar, buf+1, 1);
				int len = lenChar;
				char* name = new char[32];
				memcpy(name, buf+2, len);
				
				MVTableLock->Acquire();
				
				//check if MV exists on this server
				std::map<std::string,int>::iterator it;
				it = MVNameMap.find(name);
				if(it == MVNameMap.end()) //not found
				{
					char* regbuf = new char[MaxMailSize];
					if (!regbuf)
					{	
						printf("%s","Registration buffer couldn't be created for some reason\n");
						MVTableLock->Release();
						break;
					}
					
					char scName = NO_MV;
					memcpy(regbuf, &scName, 1);
					
					//Create and send mail
					PacketHeader outPktHdr;
					MailHeader outMailHdr;
					
					outPktHdr.to = inPktHdr.from; 
					outMailHdr.to = 1; //send reply to IST
					outMailHdr.from = 1;
					outMailHdr.length = MaxMailSize;
					
					bool success = postOffice->Send(outPktHdr, outMailHdr, regbuf); 
					if ( !success ) {
					  printf("The postOffice Send for NO_MV failed. The other server is not running!\n");
					  MVTableLock->Release();
					  break;
					}
				}else{
					int MVIndex = it->second;
					//convert to unique ID Number
					MVIndex += machineID * MAX_SERVER_MV;
					
					char* regbuf = new char[MaxMailSize];
					if (!regbuf)
					{	
						printf("%s","Registration buffer couldn't be created for some reason\n");
						MVTableLock->Release();
						break;
					}
					
					char scName = HAVE_MV;
					memcpy(regbuf, &scName, 1);
					memcpy(regbuf+1, &MVIndex, 8);
					
					//Create and send mail
					PacketHeader outPktHdr;
					MailHeader outMailHdr;
					
					outPktHdr.to = inPktHdr.from; 
					outMailHdr.to = 1; //send reply to IST
					outMailHdr.from = 1;
					outMailHdr.length = MaxMailSize;
					
					bool success = postOffice->Send(outPktHdr, outMailHdr, regbuf); 
					if ( !success ) {
					  printf("The postOffice Send for HAVE_MV failed. The other server is not running!\n");
					  MVTableLock->Release();
					  break;
					}
				}
				MVTableLock->Release();
				break;
			}
			
			case HAVE_Lock:
			{
				printf("Server %d IST received %s message!\n", machineID, "HAVE_Lock");
				repliesRemaining -= 1;
				
				if(offServerID != -1)
				{
					printf("WARNING! More than one server claims this Lock!\n");
				}
				
				//copy value from message
				memcpy(&offServerID, buf+1, 8);
				
				//if all replies received, wake the primary
				if(repliesRemaining == 0)
				{
					replyLock->Acquire();
					replyCond->Broadcast(replyLock);
					replyLock->Release();
				}
				
				break;
			}
			
			case HAVE_Cond:
			{
				printf("Server %d IST received %s message!\n", machineID, "HAVE_Cond");
				repliesRemaining -= 1;
				
				if(offServerID != -1)
				{
					printf("WARNING! More than one server claims this Cond!\n");
				}
				
				//copy value from message
				memcpy(&offServerID, buf+1, 8);
				
				//if all replies received, wake the primary
				if(repliesRemaining == 0)
				{
					replyLock->Acquire();
					replyCond->Broadcast(replyLock);
					replyLock->Release();
				}
				
				break;
			}
			
			case HAVE_MV:
			{
				printf("Server %d IST received %s message!\n", machineID, "HAVE_MV");
				repliesRemaining -= 1;
				
				if(offServerID != -1)
				{
					printf("WARNING! More than one server claims this MV!\n");
				}
				
				//copy value from message
				memcpy(&offServerID, buf+1, 8);
				
				//if all replies received, wake the primary
				if(repliesRemaining == 0)
				{
					replyLock->Acquire();
					replyCond->Broadcast(replyLock);
					replyLock->Release();
				}
				
				break;
			}
			
			case NO_Lock:
			{
				printf("Server %d IST received %s message!\n", machineID, "NO_Lock");
				repliesRemaining -= 1;
				
				//if all replies received, wake the primary
				if(repliesRemaining == 0)
				{
					replyLock->Acquire();
					replyCond->Broadcast(replyLock);
					replyLock->Release();
				}
				
				break;
			}
			
			case NO_Cond:
			{
				printf("Server %d IST received %s message!\n", machineID, "NO_Cond");
				repliesRemaining -= 1;
				
				//if all replies received, wake the primary
				if(repliesRemaining == 0)
				{
					replyLock->Acquire();
					replyCond->Broadcast(replyLock);
					replyLock->Release();
				}
				
				break;
			}
			
			case NO_MV:
			{
				printf("Server %d IST received %s message!\n", machineID, "NO_MV");
				repliesRemaining -= 1;
				
				//if all replies received, wake the primary
				if(repliesRemaining == 0)
				{
					replyLock->Acquire();
					replyCond->Broadcast(replyLock);
					replyLock->Release();
				}
				
				break;
			}
			
			case IST_LockExists:
			{
				printf("Server %d IST received %s message!\n", machineID, "IST_LockExists");
				
				int lockID = 0;
				memcpy(&lockID, buf+1, 8);
				
				if(!createdSL[lockID])
				{
					//send bad lock
					char* repbuf = new char[MaxMailSize];
					if (!repbuf)
					{	
						printf("%s","Reply buffer couldn't be created for some reason\n");
						lockTableLock->Release();
						break;
					}
					
					char scName = IST_BadLock;
					memcpy(repbuf, &scName, 1);
					
					//Create and send mail
					PacketHeader repPktHdr;
					MailHeader repMailHdr;
					
					repPktHdr.to = inPktHdr.from;
					repMailHdr.to = inMailHdr.from;
					repMailHdr.from = 1;
					repMailHdr.length = MaxMailSize;
					
					printf("Sending Bad Lock\n");
					
					bool success = postOffice->Send(repPktHdr, repMailHdr, repbuf); 
					if ( !success ) {
					  printf("The postOffice Send for BadLock failed. You must not have the other Nachos running.\n");
					}
				}else{
					//send GoodLock
					char* repbuf = new char[MaxMailSize];
					if (!repbuf)
					{	
						printf("%s","Reply buffer couldn't be created for some reason\n");
						lockTableLock->Release();
						break;
					}
					
					char scName = IST_GoodLock;
					memcpy(repbuf, &scName, 1);
					
					//Create and send mail
					PacketHeader repPktHdr;
					MailHeader repMailHdr;
					
					repPktHdr.to = inPktHdr.from;
					repMailHdr.to = inMailHdr.from;
					repMailHdr.from = 1;
					repMailHdr.length = MaxMailSize;
					
					printf("Sending Bad Lock\n");
					
					bool success = postOffice->Send(repPktHdr, repMailHdr, repbuf); 
					if ( !success ) {
					  printf("The postOffice Send for BadLock failed. You must not have the other Nachos running.\n");
					}
				}
				
				break;
			}
			
			case IST_GoodLock:
			{
				printf("Server %d IST received %s message!\n", machineID, "IST_GoodLock");
				replyLock->Acquire();
				goodLock = true;
				replyCond->Signal(replyLock);
				replyLock->Release();
				break;
			}
			
			case IST_BadLock:
			{
				printf("Server %d IST received %s message!\n", machineID, "IST_BadLock");
				replyLock->Acquire();
				goodLock = false;
				replyCond->Signal(replyLock);
				replyLock->Release();
				break;
			}
			
			default:
			{
				printf("ERROR: Server %d IST received unknown message type %d!\n", machineID, msgID);
				break;
			}
		
		}
		currentThread->Yield();
	}
}
